#!/usr/bin/env python
# -*- coding: utf-8; -*-
import datetime
import json

from django.conf import settings
from django.shortcuts import render, redirect, HttpResponse
from django_redis import get_redis_connection

from utils.alipay import AliPay
from utils.encrypt import uid
from web import models


def index(request):
    # 一般我们额外提供一个上下文字典变量给 render 函数，

    # 登录成功时 session 保存了 user_id ，中间件又读取该数据修改 request 对
    # 象内容，下面的render函数第一个参数已经包含了 session 数据。所以渲染首
    # 页时可以自动决定是否显示登录后的主页
    return render(request, 'web/index.html')


def price(request):
    """ 套餐 """
    # 获取套餐
    policy_list = models.Package.objects.filter(category=2)
    return render(request, 'web/price.html', {'policy_list': policy_list})


def payment(request, policy_id):
    """ 支付页面"""
    # 1. 价格策略（套餐）policy_id
    policy_object = models.Package.objects.filter(id=policy_id,
                                                  category=2).first()
    if not policy_object:
        return redirect('price')

    # 2. 要购买的数量
    number = request.GET.get('number', '')
    if not number or not number.isdecimal():
        return redirect('price')
    number = int(number)
    if number < 1:
        return redirect('price')

    # 3. 计算原价
    origin_price = number * policy_object.price

    # 4.之前购买过套餐(之前掏钱买过）
    balance = 0
    _object = None
    if request.tracer.package.category == 2:
        # 找到之前订单：总支付费用 、 开始~结束时间、剩余天数 = 抵扣的钱
        # 原实际支付价格
        _object = models.Transaction.objects.filter(
            user=request.tracer.user, status=2).order_by('-id').first()
        total_timedelta = _object.end_datetime - _object.start_datetime
        balance_timedelta = _object.end_datetime - datetime.datetime.now()
        if total_timedelta.days == balance_timedelta.days:
            # balance = _object.price / total_timedelta.days * (balance_timedelta.days - 1)
            # 计算抵扣金额
            balance = _object.package * price * _object.count / total_timedelta.days * (balance_timedelta.days - 1)
        else:
            balance = _object.package * price * _object.count / total_timedelta.days * balance_timedelta.days


    if balance >= origin_price:
        return redirect('price')

    context = {
        'policy_id': policy_object.id,
        'number': number,
        'origin_price': origin_price,
        'balance': round(balance, 2),
        'total_price': origin_price - round(balance, 2)
    }
    conn = get_redis_connection()
    key = 'payment_{}'.format(request.tracer.user.phone)
    # ex（表示超时时间） ps：nx=True, 表示 redis 中已存在 key，再次执行时候就不会再设置了。
    conn.set(key, json.dumps(context), ex=60 * 30)

    context['policy_object'] = policy_object
    context['transaction'] = _object

    return render(request, 'web/payment.html', context)


def pay(request):
    """将相关代码封装到 alipay.py 后对应的函数，生成并重定向到支付宝付款链接"""
    conn = get_redis_connection()
    key = 'payment_{}'.format(request.tracer.user.phone)
    context_string = conn.get(key)
    if not context_string:
        return redirect('price')
    context = json.loads(context_string.decode('utf-8'))

    # 1. 数据库中生成交易记录（待支付）
    #     等支付成功之后，我们需要把订单的状态更新为已支付、开始&结束时间
    order_id = uid(request.tracer.user.phone)
    total_price = context['total_price']
    models.Transaction.objects.create(status=1,
                                      order=order_id,
                                      user=request.tracer.user,
                                      package_id=context['policy_id'],
                                      count=context['number'],
                                      price=total_price)
    """本地使用私钥签名，支付宝使用我么上传的公钥解密。处理完支付后，支付宝可能
用“自己的私钥”添加了签名到 POST 请求中，我们需要在 notify_url 对应的视图中
使用支付宝公钥对该签名进行解密，并验证是否时支付宝发送的状态回执"""
    # 生成支付链接
    ali_pay = AliPay(appid=settings.ALI_APPID,
                     app_notify_url=settings.ALI_NOTIFY_URL,
                     return_url=settings.ALI_RETURN_URL,
                     app_private_key_path=settings.ALI_PRI_KEY_PATH,
                     alipay_public_key_path=settings.ALI_PUB_KEY_PATH)

    query_params = ali_pay.direct_pay(
        subject="trace VIP",  # 商品简单描述
        out_trade_no=order_id,  # 商户订单号
        total_amount=total_price)

    # import sys
    # if sys.version_info.major > 2 and sys.version_info.minor > 7:
    #     import time
    #     del time.clock
    #     time.clock = time.process_time

    print("********** AliPay BEG ********************")
    pay_url = "{}?{}".format(settings.ALI_GATEWAY, query_params)
    print("********** AliPay END ********************")

    print(pay_url)

    return redirect(pay_url)


"""
对于 PC 网站支付的交易，在用户支付完成之后，支付宝会根据 API 中商户传入的
notify_url，通过 POST 请求的形式将支付结果作为参数通知到商户系统。

其中返回的参数中有订单号、签名等信息，签名可帮助商户用于检查发送到
notify_url 的 POST 请求是否由支付宝发送，避免恶意人员伪造支付成功。商户持有
支付宝公钥，可以使用该公钥对支付宝成功后返回的信息中的签名解密、验证

"""


def pay_notify(request):
    """处理支付宝支付成功之后发送的 notify POST请求，由于测试时为局域网，这里
处理 GET 请求模拟对真实的 POST 请求的处理"""
    ali_pay = AliPay(appid=settings.ALI_APPID,
                     app_notify_url=settings.ALI_NOTIFY_URL,
                     return_url=settings.ALI_RETURN_URL,
                     app_private_key_path=settings.ALI_PRI_KEY_PATH,
                     alipay_public_key_path=settings.ALI_PUB_KEY_PATH)

    if request.method == 'GET':
        # 只做跳转，判断是否支付成功了，不做订单的状态更新。
        # 支付包返回订单号等：获取订单ID，然后根据订单ID做状态更新 + 认证。
        # 支付宝公钥对支付给我返回的数据request.GET 进行检查，通过则表示这
        # 是支付宝返还的接口。
        params = request.GET.dict()
        sign = params.pop('sign', None)
        status = ali_pay.verify(params, sign)
        if status:
            """
            current_datetime = datetime.datetime.now()
            out_trade_no = params['out_trade_no']
            _object = models.Transaction.objects.filter(order=out_trade_no).first()

            _object.status = 2
            _object.start_datetime = current_datetime
            _object.end_datetime = current_datetime + datetime.timedelta(days=365 * _object.count)
            _object.save()
            """
            return HttpResponse('支付完成')
        return HttpResponse('支付失败')
    else:
        from urllib.parse import parse_qs
        body_str = request.body.decode('utf-8')
        post_data = parse_qs(body_str)
        post_dict = {}
        for k, v in post_data.items():
            post_dict[k] = v[0]

        sign = post_dict.pop('sign', None)
        status = ali_pay.verify(post_dict, sign)
        # 确认支付消息有效后，保存到数据库
        if status:
            current_datetime = datetime.datetime.now()
            out_trade_no = post_dict['out_trade_no']
            _object = models.Transaction.objects.filter(
                order=out_trade_no).first()

            _object.status = 2
            _object.start_datetime = current_datetime
            _object.end_datetime = current_datetime + datetime.timedelta(
                days=365 * _object.count)
            _object.save()
            # 向支付宝后端发送 success, 表示收到
            return HttpResponse('success')

        return HttpResponse('error')
